--
-- Author:      name
-- DateTime:    2022-08-21 15:57:48
-- Description: 游戏主逻辑
local FSM = require("fsm")
local cjson = require("cjson")

local table_insert = table.insert
local table_remove = table.remove
local math_floor = math.floor


local DeskBase = require("games.common.desk")
local M = DeskBase:extend("Desk")

function M:ctor()
	--注意写上这个是为了让更新基类时，对象能同步上变更，但要注意同名函数可能会产生覆盖
	M.super:setModuleName("games.common.desk")
	M.super.ctor(self)
	self:register()
end

function M:register()
	if self.test then
		self:test()
	end
end

----------------------------------------------------------------------------------------------
---------开始游戏
----------------------------------------------------------------------------------------------
function M:init()
	print("___开始游戏___")
	self.users = {}

	self.closed = false --桌子关闭
	self.goin_balls = {} --进洞的球
	self.cur_goin_balls = {} --本轮操作的进球
	self.has_goin_balls = {}

	self.seat_count = 2
	self.start_play_limit = 2 --开始游戏需要的人数
	self.oper_timer = new("base.timer")
	self.oper_timer_id = 0 --定时器id
	self.cur_oper = nil --当前操作者
	self.cur_oper_seat_id = nil --当前操作者位置
	self.syncball_index = 0 --同步球位置的帧
	self.winner = nil --胜利者
	self.cueball_id = 22 --白球id
	self.change_player = false --是否切换玩家
	self.red_ball_goin = 0 --红球进了没有
	self.back_balls = {} --需要重置的球

	--状态名
	self.s_stage_start = "start"
	self.s_stage_play   = "play"
	self.s_stage_move   = "move"
	self.s_stage_over 	   = "over"
	self.s_stage_rest 	   = "rest"
	--状态时间
	self.stateTime = {
		start = 2,		--开始
		oper = 15,		--开始玩家操作
		move = 15,      --球的移动
		over = 1, 		--结束游戏
		rest = 2,		--等待
	}

	--游戏状态
	self.state_num ={
		[self.s_stage_start] = 1,
		[self.s_stage_play] = 2,
		[self.s_stage_move] = 3,
		[self.s_stage_over] = 4,
		[self.s_stage_rest] = 5,
	}
	--休息，开始玩家操作，抢庄, 下注，发牌，结算
	--state1 --eventName --state2 --callback
	self.stateTable = {
		{"rest", 	"to_start", 	"start", 	function() self:stStart() end }, --state start
		{"start", 	"to_play",		"play", 	function() self:stPlay() end },
		{"play", 	"to_move",		"move", 	function() self:stMove() end },
		{"move", 	"to_play",		"play", 	function() self:stPlay() end },
		{"move", 	"to_over",		"over", 	function() self:stOver() end },
		{"play", 	"to_over",		"over", 	function() self:stOver() end },
		{"over", 	"to_rest",		"rest", 	function() self:stReset() end },

		{"start", 	"to_over",		"over", 	function() self:stOver() end },
		{"play", 	"to_over",		"over", 	function() self:stOver() end },
		{"move", 	"to_over",		"over", 	function() self:stOver() end },
	}
	self.fsm = FSM.new(self.stateTable)

	--启动状态机
	self.fsm:set("over")
	self.fsm:fire("to_rest")

	g.loop(100, function()
		self:update()
	end)
	--self:test()
end

--定时检测桌子
function M:update()
	local cd_time = self.oper_timer:getCD(self.oper_timer_id)
	if cd_time and cd_time>0 then
		print("#########"..g.tid, self:getStage(), cd_time)
	end

	if not self.check_desk then
		self.check_desk = true
		local time_id = self.oper_timer_id
		g.timeout(30, function()
			if self:getStage() ~= self.s_stage_rest and self.oper_timer:getCurrId() == time_id then
				--卡住了
				g.log:deskErr("the desk state is err, auto close it! ", g.user_mgr:getUsersNum())
				g.sendGames("close_game", g.tid)
			end
			self.check_desk = false
		end)
	end
	--如果只有一个人在桌子里，超过一定时间应该踢出这个人

end

-------------------------------------------------------------------------------
-- private
-------------------------------------------------------------------------------
--重置数据
function M:reset()
	g.rule:shuffle()
	--设置在线玩家状态
	local users = g.user_mgr:getUsers()
	for _, user  in pairs(users) do
		user:reset()
	end
	self.players = {} --参与游戏的玩家
	self.goin_balls = {} --进洞的球
	self.cur_goin_balls = {} --本轮操作的进球
	self.has_goin_balls = {}
	self.cur_oper = nil --当前操作者
	self.cur_oper_seat_id = nil --当前操作者位置
	self.syncball_index = 0 --同步球位置的帧
	self.winner = nil --胜利者
	self.change_player = false --是否切换玩家
	self.red_ball_goin = 0 --红球进了没有
	self.back_balls = {} --需要重置的球
end

--操作时间
function M:getOperCDTime()
	--local num = self:getStageNum()
	local time = self.oper_timer:getCD(self.oper_timer_id) or 0
	return math_floor(time)
end

-------------------------------------------------------------------------------
-- 状态
-------------------------------------------------------------------------------

--开始
function M:stStart()
	--[[
		设置玩家状态
		洗牌
		通知玩家开始游戏

	]]
	g.log:deskDebug(0, "onStart")
	self:createRoundId() --新建牌局id
	self.round_start_time = g.time()
	self.round_num = self.round_num + 1
	self.change_player = true
	--设置玩家状态
	local users = g.user_mgr:getSeatUsers()
	for sid, user in pairs(users) do
		user:setStatus(user.s_status_gaming)
		user:addRound()
		--参与过这一局的都记录下
		self:addPlayer(user)
	end


	--给玩家发广播消息
	self:pushStart()

	local callback = function ()
		self:changeStage(self.s_stage_play)
	end
	self.oper_timer_id = self.oper_timer:timeout(self.stateTime.start, callback)
end

--下一个操作者
function M:findNextOper()
	--应该有先有庄，从庄的下一位开始
	local seat_id = self.cur_oper_seat_id
	if not self.cur_oper_seat_id then
		return g.user_mgr:getSeatUser(1)
	end

	local count = seat_id + self.seat_count
	local tmp_seat_id = 0
	for i = seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			return user
		end
	end
	return
end

--玩家操作
function M:playerOper(stage)
	g.log:deskDebug(0, "playerOper", stage, #self.cur_goin_balls)
	if self:checkOver() then
		self:changeStage(self.s_stage_over)
		return true
	end

	--当可操作人数少于2时直接跳过(2个人玩有1个弃牌
	local playing_num = g.user_mgr:getPlayingUserNum()
	if playing_num == 1 then
		--都弃牌了
		self:changeStage(self.s_stage_over)
		return true
	end
	g.log:debug("playerOper", self.change_player, self.red_ball_goin)
	if self.change_player then
		self.change_player = false
		--如果红球已进
		if self.red_ball_goin == 2 then
			g.log:debug("1111111111111red_ball_goin", self.red_ball_goin)
			--把红球退出来
			local bid = self.cur_oper.red_ball_goin
			self.red_ball_goin = 0
			self.cur_oper.red_ball_goin = nil
			--local ball = g.rule:getBall(bid)
			--if ball then
			--	ball:reset() --重置状态
			--	--把红球退出来
			--	local data = {
			--		mid = self.cur_oper:getUid(),
			--		tid = g.tid,
			--		ball = g.rule:getBallInfo(bid),
			--		balls = self.cur_oper:getBalls(),
			--	}
			--	self:sendUsers("SN_2C_back_ball", data)
			--end
			table_insert(self.back_balls, {uid=self.cur_oper:getUid(), bid = bid})
		end
		--获取当前操作的玩家，等待其操作
		local next_oper = self:findNextOper()
		--没有下个操作者，进入下一轮
		if not next_oper then
			if playing_num >= self.start_play_limit then
				self:nextStage()
				return true
			else
				self:changeStage(self.s_stage_over)
			end
			return
		end
		if self.cur_oper and next_oper:isSame(self.cur_oper) then
			g.log:deskInfo(0, "playerOper oper is same one:", self.cur_oper_seat_id)
			self:nextStage()
			return true
		end
		self.cur_oper = next_oper
		self.cur_oper_seat_id = self.cur_oper:getSeatId()

	else
		--如果红球已进
		if self.red_ball_goin == 1 then
			--锁定
			self.red_ball_goin = 2
		elseif self.red_ball_goin == 2 then
			self.red_ball_goin = 3
		end
	end
	self:pushBallBack()
	self:pushNextOper()

	--设置个超时，如果不操作就自动操作弃牌
	local function fun()
		if not self.cur_oper then return end
		self.cur_oper:addNoOperNum()
		--离线状态检查
		-- self.cur_oper:checkLeave()
		--超时3次认输
		if self.cur_oper:getNoOperNum() >= 2 then
			self.cur_oper:setStatus(self.cur_oper.s_status_giveup)
		end
		self.change_player = true
		self:playerOper()
	end
	local oper_time = self.stateTime.oper
	-- if self.cur_oper:getAutoPlay() == 1 then
	-- 	oper_time = 1.5
	-- end
	--操作定时
	self.oper_timer_id = self.oper_timer:timeout(oper_time, fun)

end

--开始操作
function M:stPlay()
	g.log:debug("_______ps stPlay")

	self:playerOper()

end

--球的移动状态
function M:stMove()
	g.log:debug("_______ps stMove")
	local callback = function ()
		print("stMove time end")
		if #self.cur_goin_balls == 0 then
			self.change_player = true
		end
		if self:getStage() == self.s_stage_move then
			self:changeStage(self.s_stage_play)
		end
	end
	self.oper_timer_id = self.oper_timer:timeout(self.stateTime.move, callback)
end

--游戏结束
function M:stOver()
	g.log:deskInfo(0, "game over")
	self.winner = g.rule:getWinner()
	self:addChip() --给玩家加币
	self:pushGameOver()
	local callback = function ()
		self.fsm:fire("to_rest")
	end
	g.timeout(self.stateTime.over, callback)
end

--休息
function M:stReset()
	g.log:deskInfo(0, "stReset")
	--重置数据
	self:reset()
	self:checkUser()
	local user_num = 0
	--有2个以上的玩家才可以开始玩
	g.fork(function()
		::CHECK_STAR::
		while true do
			user_num = g.user_mgr:getSeatUsersNum()
			self:checkUser()
			if self.closed then
				return true
			end
			if user_num >= self.start_play_limit then
				break
			end
			--print("111111111111111stReset", user_num)
			g.sleep(100)
		end
		local user_num = g.user_mgr:getSeatUsersNum()
		if user_num >= self.start_play_limit then
			self:changeStage(self.s_stage_start)
			return true
		else
			goto CHECK_STAR
		end
	end)

end

--改变状态
function M:changeStage(state)
	g.log:info("changeStage:",self.cur_stage, state)
	if not state then
		return
	end
	if self.cur_stage == state then
		print("changeStage self.cur_stage == state", state)
		assert(false, "changeStage")
		return
	end
	self.oper_timer:deltimer(self.oper_timer_id) --关闭定时器
	g.fork(function()
		self.cur_stage = state
		--self.cur_oper = nil
		--self.cur_oper_seat_id = nil
		--local users = self:getPlayers()
		--for _, user in pairs(users) do
		--end

		self.fsm:fire("to_"..state)
		self.cur_goin_balls = {}
		self.has_goin_balls = {}
	end)
end

function M:nextStage(sleep_time)
	print("11111111nextStage")
	if sleep_time then
		g.sleep(sleep_time)
	end
	local state = 0
	if not self.cur_stage then
		state = self.s_stage_start
	else
		local state_num = self.state_num[self.cur_stage]
		print("###Desk nextStage ", self.cur_stage, state_num)
		state_num = (state_num + 1) % #self.stateTable
		local state_info = self.stateTable[state_num]
		state = state_info[3]
	end
	--self.oper_timer_id = 0
	self:changeStage(state)
end
----------------------------------
-- 数据操作
----------------------------------

--检查用户状态
function M:checkUser()
	--如果玩家已离线，踢出
	local users = g.user_mgr:getUsers()
	for uid, user in pairs(users) do
		if self.closed then
			local sid = user:getSeatId()
			if user:isSeating() then
				g.user_mgr:standUp(uid)
				self:sendUsers("TS_2C_standupBc", {
					mid = uid,
					tid = g.desk_id,
					seatid = sid,
				})
			end
			self:backChip(user)
			self:sendUsers("TS_2C_leaveBc", {
				mid = uid,
				tid = g.desk_id,
				seatid = sid,
			})
			g.user_mgr:removeUser(uid)
			return
		end
	end

	local users = g.user_mgr:getSeatUsers()
	for sid, user in pairs(users) do
		local uid = user:getUid()
		local no_oper_num = user:getNoOperNum()
		if no_oper_num > 0 then
			user:addNoOperRound()
		end
		local no_oper_round = user:getNoOperRound()
		--如果玩家已经不够币, 站起
		--无操作2数, 站起
		if user:getChip() <= 0 or no_oper_round > g.const.room.no_oper_round then
			g.log:deskDebug(uid, "checkUser no_oper_round:",user:getChip(), no_oper_round, g.const.room.no_oper_round)
			g.user_mgr:standUp(uid)
			--从user_manager中删除
			self:sendUsers("TS_2C_leaveBc", {
				mid = uid,
				tid = g.desk_id,
				seatid = sid,
			})
			g.user_mgr:removeUser(uid)

		end
	end


end

--状态数字
function M:getStageNum()
	local stage = self:getStage()
	return self.state_num[stage] or 0
end

function M:pushStart()
	local tb = {
		mids={},
		chips={},
	}
	local users = self:getPlayers() --入局了的玩家
	for _, user in pairs(users) do
		table_insert(tb.mids, user:getUid())
		table_insert(tb.chips, user:getChip())
	end
	local data = {
		tid = g.tid,
		msg = cjson.encode(tb),
		lid = tostring(self.lid),
		balls = g.rule:getBallsInfo(),
	}
	self:sendUsers("SN_2C_gamebegin", data)

	--g.log:deskDebug("pushStart:", data)
end

--有玩家坐下时
function M:sitDownCallback(uid)



	local nums = g.user_mgr:getSeatPlayerNum()
	if nums == 1 and g.rid == 1 then
		g.timeout(2, function()
			--人数不够时先自己加一个进来
			g.robot:reqEnter()
		end)
	end


	return
end

--下一个下注的用户
function M:pushNextOper()
	local data = {
		tid = g.desk_id,
		mid = self.cur_oper:getUid(),
		seatid = self.cur_oper:getSeatId(),
		time = self.stateTime.oper,
		delay = self.oper_timer:getCD(self.oper_timer_id),
	}
	--print("##########pushNextOper####", tostring(data))
	self:sendUsers("SN_2C_next_oper", data)
	self.syncball_index = 0
	--print("55555555", self.cur_oper:getUid(), self.cur_oper:isRobot(), g.rid)
	--机器人操作
	if self.cur_oper:isRobot() and g.rid == 1 then
		g.timeout(2, function()
			if self:getStage() ~= self.s_stage_play or self.closed then
				return
			end
			g.robot:oper()
			self:onHitBall()
		end)
	end

end

function M:pushGameOver()
	local win_uid = self.winner:getUid()
	local win_chip = self.winner:getWinChip()
	local data = {
		tid = g.tid,
		lid = tostring(self.lid),
		msg = "",
		winner = win_uid,
		win_chip = win_chip,
	}
	g.log:deskInfo("##########pushGameOver####", tostring(data))
	self:sendUsers("SN_2C_gameend", data)
end


--返回桌子信息
function M:getDeskInfo(uid)
	--print("#############getDeskInfo_________", uid)
	--[[
	    code 0 : integer
        msg 1 : string
        tid 2 : string #桌子id
        rid 3 : integer #房间id
        rtype 4 : integer #房间类型 1比赛场
        info 5 : string #桌子信息
	]]
	--local cfg = g.room_cfg
	local user = g.user_mgr:getUser(uid)
	local users = g.user_mgr:getSeatUsers()
	local seats = {}
	for k, v in pairs(users) do
		local seat = {
			mid = v:getUid(),
			seatid = v:getSeatId(),
			seat_chips = v:getChip(),
			status = v:getStatus(),
			online = v:getOnline(),
			info = v:getInfo(),
			other = "",
			balls = v:getBalls(),
		}
		table_insert(seats, seat)
	end
	local sid = user:getSeatId()
	user:setCamp(sid)
	local self_user = {}
	self_user.mid = uid
	self_user.seatid = sid
	self_user.color = sid


	local status = self:getStageNum()
	local cd_time = self:getOperCDTime()
	if status > 5 then
		cd_time = 0
	end
	local curr_mid = 0
	local curr_seatid = 0
	if self.cur_oper then
		curr_mid = self.cur_oper:getUid()
		curr_seatid = self.cur_oper_seat_id
	end
	local balls_info = {}
	if status ~= self.state_num.s_stage_rest then
		balls_info = g.rule:getBallsInfo()
	end
	local info = {
		rid = g.rid,
		tid = g.tid,
		curr_mid = curr_mid,
		curr_seatid = curr_seatid,
		cd_time = cd_time, --剩余操作时间
		all_time = self.stateTime.oper, --总时间
		status = status, --桌子状态
		seats = seats,
		--小球列表， 坐标
		balls = balls_info,
		self_user = self_user,
	}
	local res = {
		code = g.error_code.ok,
		tid = g.tid,
		rid = g.rid,
		rtype = g.rtype,
		info = cjson.encode(info),
	}

	return res
end

function M:betting()

end

--检查游戏是否结束
function M:checkOver()
	--一个玩家离线了， 超时不操作算输
	--所有球进洞了，游戏结束
	local play_num = g.user_mgr:getPlayingUserNum()
	if play_num > 0 and play_num < self.start_play_limit then
		print("11111111checkOver")
		if self:getStageNum() < self.state_num[self.s_stage_over] then
			print("11111111checkOver2")
			return true
		end
	end
	--print("11111111checkOver3",#self.goin_balls)
	--if #self.goin_balls >= 21 then
	--	return true
	--end
	return false
end

--离线处理
function M:disconnectCallback(user)
	local uid = user:getUid()
	local seat_id = user:getSeatId()
	--如果只剩下一个玩家则退出游戏
	local play_num = g.user_mgr:getSeatUsersNum()
	--旁观者掉线马上踢出桌子
	if play_num <= 1 or not user:isSeating() then
		self:backChip(user)
		if user:isSeating() then
			g.user_mgr:standUp(uid)
			self:sendUsers("TS_2C_standupBc", {
				mid = uid,
				tid = g.tid,
				seatid = seat_id,
			})
		end
		--从user_manager中删除
		g.user_mgr:removeUser(uid)
		self:sendUser(user, "TS_2C_leaveBc", {
			mid = uid,
			tid = g.desk_id,
			seatid = seat_id,
		})
		print("disconnectCallback旁观者掉线马上踢出桌子", uid, seat_id)
		return true
	end
	return true
end

function M:onHitBall(uid)
	--if uid ~= self.cur_oper:getUid() then
	--	g.log:deskErr(uid, "onHitBall", self.cur_oper:getUid())
	--	return
	--end
	self:changeStage(self.s_stage_move)
	--self.oper_timer:deltimer(self.oper_timer_id)
	--self.oper_timer_id = nil
end

function M:onBallStop(msg)
	g.rule:setBalls(msg)
	if #self.cur_goin_balls == 0 then
		self.change_player = true
	end
	if self:getStage() == self.s_stage_move then
		self:changeStage(self.s_stage_play)
	end
	g.rule:syncBalls(msg.balls)
end

function M:onBallGoin(msg)
	g.log:debug("onBallGoin:", msg)
	local res = {code = 0}
	local ball_info = msg.ball
	local bid = ball_info.id
	if not self.has_goin_balls then self.has_goin_balls = {} end
	if self.has_goin_balls[bid] then
		return res
	end
	self.has_goin_balls[bid] = true
	table.insert(self.goin_balls, ball_info)
	--g.log:debug("onBallGoin:11111111",msg.uid, bid)
	local ball = g.rule:getBall(bid)
	ball:setGoin(ball_info.goin)
	--ball.goin = ball_info.goin
	local kind = ball:getKind()
	local user = self:getUserByCamp(kind) --进球属于那个玩家的
	if ball:isRedBall() then
		--红球
		user = self.cur_oper
	end
	g.log:debug("self.cur_oper:getCamp()", self.cur_oper:getCamp(), self.cur_oper:getSeatId())
	if user then
		if ball:isRedBall() then
		else
			user:addBall(bid)
		end

		--print("onBallGoin:", kind, uid, tostring(user:getBalls()))
		--g.log:debug("onBallGoin:", kind )
		--g.log:debug("onBallGoin:222222222", user:getUid(), bid, kind)
		--g.log:debug("onBallGoin:333333333", user:getUid(), user:getBalls())
		res = {code = 0, mid = user:getUid(), balls = user:getBalls()}
		local data = {
			mid = user:getUid(),
			tid = g.tid,
			balls = user:getBalls()
		}
		self:sendUsers("SN_2C_ball_goin", data)
	end
	if self.cur_oper:getCamp() == kind then
		--进的是自己阵营的球
		table.insert(self.cur_goin_balls, ball_info)

	else
		--切换球权
		self.change_player = true
		--进的母球把之前进的一个球给还回来
		if ball:isCueBall() then
			local bid = self.cur_oper:getBall()
			if bid then
				--local ball = g.rule:getBall(bid)
				--if ball then
				--	ball:reset()
				--	local data = {
				--		mid = self.cur_oper:getUid(),
				--		tid = g.tid,
				--		ball = g.rule:getBallInfo(bid),
				--		balls = self.cur_oper:getBalls(),
				--	}
				--	self:sendUsers("SN_2C_back_ball", data)
				--end
				table_insert(self.back_balls, {uid=self.cur_oper:getUid(), bid = bid})
			end
		end
		g.log:debug("22222222ball->", ball:isRedBall())
		if ball:isRedBall() then
			--红球进了
			table.insert(self.cur_goin_balls, ball_info)
			self.change_player = false
			self.red_ball_goin = 1
			self.cur_oper.red_ball_goin = bid
		end
	end
	g.log:debug(msg.uid, "onBallGoin:", kind, bid, ball_info.goin)
	if g.rule:checkOver(kind) then
		g.log:err("change over",msg.uid, kind)
		--如果红球还没进，把最后进的球退回
		if g.room_cfg.type == 2 and self.red_ball_goin == 0 then
			local bid = user:getBall()
			if bid then
				--local ball = g.rule:getBall(bid)
				--if ball then
				--	ball:reset()
				--	local data = {
				--		mid = self.cur_oper:getUid(),
				--		tid = g.tid,
				--		ball = g.rule:getBallInfo(bid),
				--		balls = self.cur_oper:getBalls(),
				--	}
				--	self:sendUsers("SN_2C_back_ball", data)
				--end
				table_insert(self.back_balls, {uid=user:getUid(), bid = bid})
			end
			return
		end
		g.timeout(1, function()
			self:changeStage(self.s_stage_over)
		end)
	end
	return res
end

function M:checkSyncBall(msg)
	local frame_index = msg.frame_index
	if self.syncball_index > frame_index then
		return false
	end
	self.syncball_index = frame_index
	g.rule:syncBalls(msg.balls)

	return true
end

function M:getRiVal(uid)
	local users = self:getPlayers()
	for k, v in pairs(users) do
		if v.uid ~= uid then
			return v
		end
	end
	return nil
end

function M:getUserByCamp(camp)
	local users = self:getPlayers()
	for k, v in pairs(users) do
		if v:getCamp() == camp then
			return v
		end
	end
end


--离桌
function M:leaveCallback(user)
	local uid = user:getUid()
	local seat_id = user:getSeatId()

	local play_num = g.user_mgr:getPlayingUserNum()
	if play_num == 1 then
		if user:isGaming() then
			if user:isPlayer() then
				g.log:deskInfo(uid, "leaveCallback", play_num, g.user_mgr:getSeatUsersNum())
			end
		end
	end
	--如果在游戏中弃牌
	if user:isGaming() then
		user:setStatus(user.s_status_giveup) --设置弃牌状态
		if self.cur_oper_seat_id == seat_id then
			self.oper_timer:deltimer(self.oper_timer_id)
		end
	end
	--站起
	if user:isSeating() then
		g.user_mgr:standUp(uid)
		self:sendUsers("TS_2C_standupBc", {
			mid = uid,
			tid = g.desk_id,
			seatid = seat_id,
		})
	end
	--返还到游戏帐户中
	self:backChip(user)
	self:sendUsers("TS_2C_leaveBc", {
		mid = uid,
		tid = g.desk_id,
		seatid = seat_id,
	})
	--删除
	g.user_mgr:removeUser(uid)
	--只剩下一个人直接结束
	local play_num = g.user_mgr:getPlayingUserNum()
	if play_num == 1 then
		if self:getStageNum() < self.state_num[self.s_stage_over] then
			self:changeStage(self.s_stage_over)
		end
	end
end

function M:enterDeskCallback(user, msg)
	if user:isSeating() then return end
	local uid = user:getUid()
	local msg = {
		["tid"]    = g.tid,
		["mid"]    = uid,
		["chips"]  = g.room_cfg.cost,
		["seatid"] = 0,
		["uid"]    = uid,
	}
	local res = g.chandler:reqSitDown(msg, false)
	if res.code > 0 then
		--坐下失败了把玩家踢出桌子
		g.log:deskErr(uid, "enterDeskCallback sitdown err", user:getChip(), g.room_cfg.cost)
		g.timeout(1, function()
			local user = g.user_mgr:getUser(uid)
			if not user then return end
			self:sendUser(user, "TS_2C_leaveBc", {
				mid = uid,
				tid = g.tid,
				seatid = 0,
			})
			--删除
			g.user_mgr:removeUser(uid)
		end)

	end

end

--对玩家输赢处理
function M:addChip()
	if not self.winner then
		return
	end
	local win_chip = g.room_cfg.cost * 2
	self.winner:setWinChip(win_chip)
	if win_chip > 0 then
		self.winner:addChip(win_chip)
	end

end

function M:pushBallBack()
	if #self.back_balls == 0 then
		return
	end
	for k, v in pairs(self.back_balls) do
		local bid = v.bid
		local uid = v.uid
		local ball = g.rule:getBall(bid)
		local user = g.user_mgr:getUser(uid)
		if ball and user then
			ball:reset() --重置状态
			--把红球退出来
			local data = {
				mid = uid,
				tid = g.tid,
				ball = g.rule:getBallInfo(bid),
				balls = user:getBalls(),
			}
			self:sendUsers("SN_2C_back_ball", data)
		end
	end
	self.back_balls = {}
end


return M